﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Forms;
using Microsoft.Web.Administration;
using Microsoft.Web.Management.Server;

namespace IISAppPoolTM
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : IDisposable
    {
        #region Private Members

        private readonly NotifyIcon _systemTrayIcon;

        #endregion

        #region Properties

        public List<ApplicationPool> ApplicationPools { get;set; }

        #endregion

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MainWindow"/> class.
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();

            // Start minimized by default
            Hide();
            
            _systemTrayIcon = new NotifyIcon { Icon = Properties.Resources.web_server, Visible = true };
            _systemTrayIcon.DoubleClick += delegate
                              {
                                  Show();
                                  WindowState = WindowState.Normal;
                              };

            // Fetch application pool list
            ApplicationPools = new List<ApplicationPool>();
            GetApplicationPoolCollection();

            RebuiltContextMenu();

            // Set the list view item suorce to the list of aplication pools
            _applicationPoolsListview.ItemsSource = ApplicationPools;
        }

        #endregion

        #region Private Methods
        
        /// <summary>
        /// Rebuilts the context menu to take newest application pool states into consideration.
        /// </summary>
        private void RebuiltContextMenu()
        {
            var recycleAll = new MenuItem("Recycle all", (o, e) => _recycleButton_Click(this, null), Shortcut.CtrlR) { Index = 0 };
            var stopAll = new MenuItem("Stop all", (o, e) => _stopButton_Click(this, null), Shortcut.CtrlS) { Index = 1 };
            var startall = new MenuItem("Start all", (o, e) => _startButton_Click(this, null), Shortcut.CtrlShiftS) { Index = 2 };

            var recycle = new MenuItem("Recycle", (o, e) => _stopButton_Click(this, null), Shortcut.CtrlShiftR) { Index = 3 };
            var stop = new MenuItem("Stop", (o, e) => _stopButton_Click(this, null), Shortcut.CtrlDel) { Index = 4 };
            var start = new MenuItem("Start", (o, e) => _stopButton_Click(this, null), Shortcut.CtrlIns) { Index = 5 };
            var exit = new MenuItem("Exit", (o, e) => Close(), Shortcut.CtrlX) {Index = 100};
            
            foreach(var pool in ApplicationPools)
            {
                if(pool.State != ObjectState.Stopped && pool.State!= ObjectState.Stopping)
                    stop.MenuItems.Add(new MenuItem(String.Format("{0} ({1})", pool.Name, pool.State), (o, e) => _stopButton_Click(pool, null)));

                if (pool.State != ObjectState.Started && pool.State != ObjectState.Starting)                
                    start.MenuItems.Add(new MenuItem(String.Format("{0} ({1})", pool.Name, pool.State), (o, e) => _startButton_Click(pool, null)));
                
                recycle.MenuItems.Add(new MenuItem(String.Format("{0} ({1})", pool.Name, pool.State), (o, e) => _recycleButton_Click(pool, null)));
            }

            _systemTrayIcon.ContextMenu = new ContextMenu();

            if(start.MenuItems.Count > 0)
                _systemTrayIcon.ContextMenu.MenuItems.Add(start);
            if (stop.MenuItems.Count > 0)
                _systemTrayIcon.ContextMenu.MenuItems.Add(stop);
            if (recycle.MenuItems.Count > 0)
                _systemTrayIcon.ContextMenu.MenuItems.Add(recycle);

            _systemTrayIcon.ContextMenu.MenuItems.AddRange(new[] { recycleAll, stopAll, startall, exit });
        }

        /// <summary>
        /// Gets the application pool collection from the server and stores them
        /// into the class variable
        /// </summary>
        [ModuleServiceMethod(PassThrough = true)]
        private void GetApplicationPoolCollection()
        {
            var serverManager = new ServerManager();
            var applicationPoolCollection = serverManager.ApplicationPools;
            foreach (ApplicationPool applicationPool in applicationPoolCollection)
                ApplicationPools.Add(applicationPool);
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Raises the <see cref="E:System.Windows.Window.StateChanged"/> event.
        /// </summary>
        /// <param name="e">An <see cref="T:System.EventArgs"/> that contains the event data.</param>
        protected override void OnStateChanged(EventArgs e)
        {
            if (WindowState == WindowState.Minimized)
                Hide();

            base.OnStateChanged(e);
        }

        /// <summary>
        /// Handles the Click event of the _stopButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void _stopButton_Click(object sender, RoutedEventArgs e)
        {
            if (e == null)
                _applicationPoolsListview.SelectAll();
            else if(sender is ApplicationPool)
            {
                _applicationPoolsListview.UnselectAll();
                _applicationPoolsListview.SelectedItem = sender;
            }

            using (var serverManager = new ServerManager())
            {
                foreach (var appPool in _applicationPoolsListview.SelectedItems.Cast<ApplicationPool>())
                {
                    if (appPool.State == ObjectState.Starting)
                    {
                        // Maxing out at 1 second of waiting time
                        var maxCount = 0;
                        while (appPool.State != ObjectState.Started && maxCount < 10)
                        {
                            Thread.Sleep(100);
                            maxCount++;
                        }
                    }

                    if (appPool.State == ObjectState.Started)
                        appPool.Stop();
                }

                // Commiting changes to the server manager
                serverManager.CommitChanges();
            }

            // Refreshing menus and listview
            _applicationPoolsListview.Items.Refresh();
            RebuiltContextMenu();
        }

        /// <summary>
        /// Handles the Click event of the _startButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void _startButton_Click(object sender, RoutedEventArgs e)
        {
            if (e == null)
                _applicationPoolsListview.SelectAll();
            else if (sender is ApplicationPool)
            {
                _applicationPoolsListview.UnselectAll();
                _applicationPoolsListview.SelectedItem = sender;
            }

            using (var serverManager = new ServerManager())
            {
                foreach (var appPool in _applicationPoolsListview.SelectedItems.Cast<ApplicationPool>())
                {
                    if (appPool.State == ObjectState.Stopping)
                    {
                        // Maxing out at 1 second of waiting time
                        var maxCount = 0;
                        while (appPool.State != ObjectState.Stopped && maxCount < 10)
                        {
                            Thread.Sleep(100);
                            maxCount++;
                        }
                    }

                    if (appPool.State == ObjectState.Stopped)
                        appPool.Start();
                }

                // Commiting changes to the server manager
                serverManager.CommitChanges();
            }

            // Refreshing menus and listview
            _applicationPoolsListview.Items.Refresh();
            RebuiltContextMenu();
        }

        /// <summary>
        /// Handles the Click event of the _recycleButton control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void _recycleButton_Click(object sender, RoutedEventArgs e)
        {
            if (e == null)
                _applicationPoolsListview.SelectAll();
            else if (sender is ApplicationPool)
            {
                _applicationPoolsListview.UnselectAll();
                _applicationPoolsListview.SelectedItem = sender;
            }

            using(var serverManager = new ServerManager())
            {              
                foreach (var appPool in _applicationPoolsListview.SelectedItems.Cast<ApplicationPool>())
                    appPool.Recycle();

                // Commiting changes to the server manager
                serverManager.CommitChanges();
            }

            // Refreshing menus and listview
            _applicationPoolsListview.Items.Refresh();
            RebuiltContextMenu();
        }

        /// <summary>
        /// Handles the Checked event of the checkBox1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void checkBox1_Checked(object sender, RoutedEventArgs e)
        {
            _applicationPoolsListview.SelectAll();
        }

        /// <summary>
        /// Handles the Unchecked event of the checkBox1 control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void checkBox1_Unchecked(object sender, RoutedEventArgs e)
        {
            _applicationPoolsListview.UnselectAll();
        }

        /// <summary>
        /// Handles the Closed event of the Window control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void Window_Closed(object sender, EventArgs e)
        {
            Dispose();
        }

        #endregion

        #region IDisposable

        /// <summary>
        /// Releases unmanaged and - optionally - managed resources
        /// </summary>
        /// <param name="disposing"><c>true</c> to release both managed and unmanaged resources; <c>false</c> to release only unmanaged resources.</param>
        public void Dispose(bool disposing)
        {
            if (disposing)
            {
                _systemTrayIcon.Dispose(); //we dispose our tray icon here
            }
        }

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            Dispose(true);
        }

        #endregion
    }
}